package com.lds.config.center.server.business.namespace.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.benmanes.caffeine.cache.Cache;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseBatchCreateRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseBatchDeleteRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseBatchUpdateRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseCreateRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseDeleteRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseGetByIdRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseGetByIdsRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseGetByKeyRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseListPageRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseListRequest;
import com.lds.config.center.common.model.namespace.request.NamespaceBaseUpdateRequest;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseBatchCreateResponse;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseBatchDeleteResponse;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseBatchUpdateResponse;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseDeleteResponse;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseListResponse;
import com.lds.config.center.common.model.namespace.response.NamespaceBaseResponse;
import com.lds.config.center.server.business.app.entity.App;
import com.lds.config.center.server.business.app.mapper.AppMapper;
import com.lds.config.center.server.business.cluster.entity.Cluster;
import com.lds.config.center.server.business.cluster.mapper.ClusterMapper;
import com.lds.config.center.server.business.env.entity.Env;
import com.lds.config.center.server.business.env.mapper.EnvMapper;
import com.lds.config.center.server.business.item.entity.Item;
import com.lds.config.center.server.business.item.mapper.ItemMapper;
import com.lds.config.center.server.business.namespace.converter.NamespaceBaseCreateRequestToEntityConverter;
import com.lds.config.center.server.business.namespace.converter.NamespaceBaseGetByKeyRequestToEntityConverter;
import com.lds.config.center.server.business.namespace.converter.NamespaceBaseListPageRequestToEntityConverter;
import com.lds.config.center.server.business.namespace.converter.NamespaceBaseListRequestToEntityConverter;
import com.lds.config.center.server.business.namespace.converter.NamespaceBaseUpdateRequestToEntityConverter;
import com.lds.config.center.server.business.namespace.converter.NamespaceToBaseResponseConverter;
import com.lds.config.center.server.business.namespace.entity.Namespace;
import com.lds.config.center.server.business.namespace.mapper.NamespaceMapper;
import com.lds.config.center.server.business.namespace.service.NamespaceBaseService;
import com.lds.config.center.server.common.enums.ServerErrorEnum;
import com.lds.config.center.server.common.model.NamespaceName;
import com.lds.management.center.common.model.db.OrderBy;
import com.lds.management.center.common.model.db.PageResult;
import com.lds.management.center.common.model.dto.ResultDTO;
import com.lds.management.center.common.util.AssertUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 基础服务实现类
 *
 * @author lidongsheng
 * @since 2025-06-26
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NamespaceBaseServiceImpl implements NamespaceBaseService {

    private final EnvMapper envMapper;
    private final ClusterMapper clusterMapper;
    private final AppMapper appMapper;
    private final NamespaceMapper namespaceMapper;
    private final ItemMapper itemMapper;
    private final NamespaceBaseCreateRequestToEntityConverter namespaceBaseCreateRequestToEntityConverter;
    private final NamespaceBaseUpdateRequestToEntityConverter namespaceBaseUpdateRequestToEntityConverter;
    private final NamespaceBaseListRequestToEntityConverter namespaceBaseListRequestToEntityConverter;
    private final NamespaceToBaseResponseConverter namespaceToBaseResponseConverter;
    private final NamespaceBaseListPageRequestToEntityConverter namespaceBaseListPageRequestToEntityConverter;
    private final NamespaceBaseGetByKeyRequestToEntityConverter namespaceBaseGetByKeyRequestToEntityConverter;
    private final Cache<Long, NamespaceName> namespaceNameCache;

    @Override
    @Transactional
    public ResultDTO<NamespaceBaseResponse> createNamespace(NamespaceBaseCreateRequest request) {
        try {
            Namespace namespace = namespaceBaseCreateRequestToEntityConverter.convert(request);
            namespaceMapper.insert(namespace);
            NamespaceBaseResponse response = namespaceToBaseResponseConverter.convert(namespace);
            return ResultDTO.success(response);
        } catch (DuplicateKeyException e) {
            return ResultDTO.fail("DATA_REPEAT", "数据重复");
        }
    }

    @Transactional
    @Override
    public ResultDTO<NamespaceBaseBatchCreateResponse> batchCreateNamespace(NamespaceBaseBatchCreateRequest request) {
        NamespaceBaseBatchCreateResponse response = NamespaceBaseBatchCreateResponse.builder()
                .responses(request.getRequests().stream().map(this::createNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<NamespaceBaseDeleteResponse> deleteNamespace(NamespaceBaseDeleteRequest request) {
        // item引用关系
        Long itemCount = itemMapper.selectCount(new QueryWrapper<>(Item.builder().namespaceId(request.getId()).build()));
        AssertUtil.assertTrue(itemCount == 0, ServerErrorEnum.ITEM_USING);


        namespaceMapper.deleteById(request.getId());

        NamespaceBaseDeleteResponse response = NamespaceBaseDeleteResponse.builder().request(request).build();
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<NamespaceBaseBatchDeleteResponse> batchDeleteNamespace(NamespaceBaseBatchDeleteRequest request) {
        NamespaceBaseBatchDeleteResponse response = NamespaceBaseBatchDeleteResponse.builder()
                .responses(request.getRequests().stream().map(this::deleteNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<NamespaceBaseResponse> updateNamespace(NamespaceBaseUpdateRequest request) {
        try {
            Namespace namespace = namespaceBaseUpdateRequestToEntityConverter.convert(request);
            namespaceMapper.updateById(namespace);
            NamespaceBaseResponse response = namespaceToBaseResponseConverter.convert(namespace);
            return ResultDTO.success(response);
        } catch (DuplicateKeyException e) {
            return ResultDTO.fail("DATA_REPEAT", "数据重复");
        }
    }

    @Transactional
    @Override
    public ResultDTO<NamespaceBaseBatchUpdateResponse> batchUpdateNamespace(NamespaceBaseBatchUpdateRequest request) {
        NamespaceBaseBatchUpdateResponse response = NamespaceBaseBatchUpdateResponse.builder()
                .requests(request.getRequests().stream().map(this::updateNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseResponse> getNamespaceById(NamespaceBaseGetByIdRequest request) {
        Namespace namespace = namespaceMapper.selectById(request.getId());
        if (namespace == null) {
            return ResultDTO.success();
        }

        NamespaceBaseResponse response = namespaceToBaseResponseConverter.convert(namespace);
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseListResponse> getNamespaceByIds(NamespaceBaseGetByIdsRequest request) {
        List<Namespace> list = request.getIds().stream().map(id -> namespaceMapper.selectById(id)).collect(Collectors.toList());
        return ResultDTO.success(NamespaceBaseListResponse.builder()
                .namespaces(list.stream().map(namespace -> namespaceToBaseResponseConverter.convert(namespace)).collect(Collectors.toList()))
                .build());
    }

    @Override
    public Namespace getNamespaceByKey(NamespaceBaseGetByKeyRequest request) {
        return namespaceMapper.selectOne(new QueryWrapper<>(namespaceBaseGetByKeyRequestToEntityConverter.convert(request)));
    }

    @Override
    public ResultDTO<NamespaceBaseListResponse> listNamespace(NamespaceBaseListRequest request) {
        QueryWrapper<Namespace> wrapper = new QueryWrapper<>(namespaceBaseListRequestToEntityConverter.convert(request));
        if (StringUtils.isNotEmpty(request.getOrderByKey())) {
            wrapper.orderByDesc(request.getOrderByKey());
        }

        List<Namespace> namespaces = namespaceMapper.selectList(wrapper);

        NamespaceBaseListResponse response = NamespaceBaseListResponse.builder()
                .namespaces(namespaces.stream().map(namespaceToBaseResponseConverter::convert).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseListResponse> listAllNamespace(OrderBy orderBy) {
        NamespaceBaseListRequest namespaceRequest = NamespaceBaseListRequest.builder().build();
        namespaceRequest.setOrderByKey(orderBy.getOrderByKey());
        return listNamespace(namespaceRequest);
    }

    @Override
    public ResultDTO<PageResult<NamespaceBaseResponse>> listNamespacePage(NamespaceBaseListPageRequest request) {
        Page<Namespace> page = new Page<>(request.getPageNum(), request.getPageSize(), true);

        QueryWrapper<Namespace> wrapper = new QueryWrapper<>(namespaceBaseListPageRequestToEntityConverter.convert(request));
        if (StringUtils.isNotEmpty(request.getOrderByKey())) {
            if (request.getOrderByDesc() != null && request.getOrderByDesc().booleanValue() == false) {
                wrapper.orderByAsc(request.getOrderByKey());
            } else {
                wrapper.orderByDesc(request.getOrderByKey());
            }
        }

        IPage<Namespace> pageResult = namespaceMapper.selectPage(page, wrapper);

        PageResult<NamespaceBaseResponse> response = new PageResult(
                pageResult.getTotal(), pageResult.getPages(), pageResult.getCurrent(), pageResult.getSize(),
                pageResult.getRecords().stream().map(namespaceToBaseResponseConverter::convert).collect(Collectors.toList()));
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseBatchCreateResponse> batchCreateNamespaceAsync(NamespaceBaseBatchCreateRequest request) {
        NamespaceBaseBatchCreateResponse response = NamespaceBaseBatchCreateResponse.builder()
                .responses(request.getRequests().parallelStream().map(this::createNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseBatchDeleteResponse> batchDeleteNamespaceAsync(NamespaceBaseBatchDeleteRequest request) {
        NamespaceBaseBatchDeleteResponse response = NamespaceBaseBatchDeleteResponse.builder()
                .responses(request.getRequests().parallelStream().map(this::deleteNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<NamespaceBaseBatchUpdateResponse> batchUpdateNamespaceAsync(NamespaceBaseBatchUpdateRequest request) {
        NamespaceBaseBatchUpdateResponse response = NamespaceBaseBatchUpdateResponse.builder()
                .requests(request.getRequests().parallelStream().map(this::updateNamespace).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public NamespaceName getNamespaceName(Long namespaceId) {
        return namespaceNameCache.get(namespaceId, this::getNamespaceNameNoCache);
    }

    private NamespaceName getNamespaceNameNoCache(Long namespaceId) {
        Namespace namespace = namespaceMapper.selectById(namespaceId);
        AssertUtil.assertTrue(Objects.nonNull(namespace), ServerErrorEnum.NAMESPACE_NOT_EXIST);

        App app = appMapper.selectById(namespace.getAppId());
        AssertUtil.assertTrue(Objects.nonNull(app), ServerErrorEnum.APP_NOT_EXIST);

        Cluster cluster = clusterMapper.selectById(app.getClusterId());
        AssertUtil.assertTrue(Objects.nonNull(cluster), ServerErrorEnum.CLUSTER_NOT_EXIST);

        Env env = envMapper.selectById(cluster.getEnvId());
        AssertUtil.assertTrue(Objects.nonNull(env), ServerErrorEnum.ENV_NOT_EXIST);

        return NamespaceName.builder()
                .envId(env.getId())
                .envName(env.getName())
                .clusterId(cluster.getId())
                .clusterName(cluster.getName())
                .appId(app.getId())
                .appName(app.getName())
                .namespaceId(namespace.getId())
                .namespaceName(namespace.getName())
                .build();
    }

}
